#ifndef _SRC_NET_CHANNEL_H_
#define _SRC_NET_CHANNEL_H_

#include <string>

#include "src/base/time_stamp.h"
#include "src/base/utils.h"

namespace fio66::net {
class EventLoop;
///
/// A selectable I/O channel.
///
/// This class doesn't own the file descriptor.
/// The file descriptor could be a socket,
/// an eventfd, a timerfd, or a signalfd
class Channel {
 public:
  DISALLOW_COPY_AND_ASSIGN(Channel)
  typedef std::function<void()> EventCallback;
  typedef std::function<void(Timestamp)> ReadEventCallback;

  Channel(EventLoop* loop, int fd);
  ~Channel();

  void HandleEvent(Timestamp receiveTime);
  void SetReadCallback(ReadEventCallback cb) { read_callback_ = std::move(cb); }
  void SetWriteCallback(EventCallback cb) { write_callback_ = std::move(cb); }
  void SetCloseCallback(EventCallback cb) { write_callback_ = std::move(cb); }
  void SetErrorCallback(EventCallback cb) { error_callback_ = std::move(cb); }

  /// Tie this channel to the owner object managed by shared_ptr,
  /// prevent the owner object being destroyed in handleEvent.
  void Tie(const std::shared_ptr<void>&);

  int Fd() const { return fd_; }
  int Events() const { return events_; }
  void SetRevents(int revt) { revents_ = revt; }  // used by pollers
  // int revents() const { return revents_; }
  bool IsNoneEvent() const { return events_ == kNoneEvent; }

  void EnableReading() {
    events_ |= kReadEvent;
    Update();
  }
  void DisableReading() {
    events_ &= ~kReadEvent;
    Update();
  }
  void EnableWriting() {
    events_ |= kWriteEvent;
    Update();
  }
  void DisableWriting() {
    events_ &= ~kWriteEvent;
    Update();
  }
  void DisableAll() {
    events_ = kNoneEvent;
    Update();
  }
  bool IsWriting() const { return events_ & kWriteEvent; }
  bool IsReading() const { return events_ & kReadEvent; }

  // for Poller
  int Index() { return index_; }
  void SetIndex(int idx) { index_ = idx; }

  // for debug
  std::string ReventsToString() const;
  std::string EventsToString() const;

  void doNotLogHup() { logHup_ = false; }

  EventLoop* OwnerLoop() { return loop_; }
  void Remove();

 private:
  static std::string EventsToString(int fd, int ev);

  void Update();
  void HandleEventWithGuard(Timestamp receiveTime);

  static const int kNoneEvent;
  static const int kReadEvent;
  static const int kWriteEvent;

  EventLoop* loop_;
  const int fd_;
  int events_;
  int revents_;  // it's the received event types of epoll or poll
  int index_;    // used by Poller.
  bool logHup_;

  std::weak_ptr<void> tie_;
  bool tied_;
  bool event_handling_;
  bool added_to_loop_;
  ReadEventCallback read_callback_;
  EventCallback write_callback_;
  EventCallback close_callback_;
  EventCallback error_callback_;
};

}  // namespace fio66::net

#endif // _SRC_NET_CHANNEL_H_
